package cn.com.infohold.smartcity.weex.update;

import android.os.Handler;
import android.os.Message;

import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.FileHeader;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * Created by apple on 2017/1/23.
 */

public class WeexUpdate extends Thread {

    private ZipHandler zipHandler;
    private ZipFile zipFile;
    private String extractPath;
    private boolean cancelled = false;

    public void cancel() {
        if (!cancelled && !interrupted())
            interrupt();
    }

    @Override
    public void run() {
        try {
            final File target = zipFile.getFile();
            final String zipName = target.getName();
            final List<FileHeader> all = zipFile.getFileHeaders();
            final List<FileHeader> list = new ArrayList<>();
            final Pattern pattern = Pattern.compile("[\\S\\s]+-(\\d+\\.\\d+\\.\\d+)\\.zip$");
            final Matcher matcher = pattern.matcher(zipName);
            String version;
            if (matcher.find()) {
                version = matcher.group(1);
            } else {
                throw new ZipException("not found dist file.");
            }
            for (FileHeader fileHeader : all) {
                String fileName = fileHeader.getFileName();
                if (fileName.startsWith("dist")) {
                    list.add(fileHeader);
                }
            }
            final int totalCount = list.size();

            int i = 1;
            int percent = 0;
            int lastP = percent;
            for (FileHeader item : list) {
                if (cancelled) {
                    Message message = new Message();
                    message.what = ZipHandler.RESULT_CANCELLED;
                    zipHandler.sendMessage(message);
                    return;
                }
                String fileName = item.getFileName();
                int index = fileName.indexOf("/");
                String path = index != -1 ? fileName.substring(fileName.indexOf("/")) : fileName;
                File dir = new File(extractPath);
                zipFile.extractFile(item, dir.getAbsolutePath(), null, path);
                percent = (int) (1.0F * i / totalCount * 100);
                if (percent > lastP) {
                    Message message = new Message();
                    message.what = ZipHandler.RESULT_WORKING;
                    message.arg1 = percent;
                    message.obj = fileName;
                    zipHandler.sendMessage(message);
                }
                lastP = percent;
                i++;
            }
            Message message = new Message();
            message.what = ZipHandler.RESULT_SUCCESS;
            message.obj = version;
            zipHandler.sendMessage(message);
//            zipFile.extractFile(fileHeader, new File(extractPath, fileName).getAbsolutePath());       // 将文件抽出到解压目录(解压)
        } catch (Exception e) {
            Message message = new Message();
            message.what = ZipHandler.RESULT_ERROR;
            message.obj = e;
            zipHandler.sendMessage(message);
        } finally {
            Message message = new Message();
            message.what = ZipHandler.RESULT_FINISH;
            zipHandler.sendMessage(message);
        }
    }

    public void unzip(File from, String to, OnUpdateListening listening) throws ZipException {
        unzip(from, to, null, listening);
    }

    public void unzip(File from, String to, String pwd, OnUpdateListening listening) throws ZipException {
        extractPath = to;
        zipFile = new ZipFile(from);  // 首先创建ZipFile指向磁盘上的.zip文件
        zipFile.setFileNameCharset("UTF-8");       // 设置文件名编码，在GBK系统中需要设置
        if (!zipFile.isValidZipFile()) {      // 验证.zip文件是否合法，包括文件是否存在、是否为zip文件、是否被损坏等
            throw new ZipException("zip file is not valid.");
        }
        File destDir = new File(to);        // 解压目录
        if (destDir.isDirectory() && !destDir.exists()) {
            destDir.mkdir();
        }
        if (zipFile.isEncrypted() && pwd != null) {
            zipFile.setPassword(pwd.toCharArray());   // 设置密码
        }
        zipFile.setRunInThread(false); //true 在子线程中进行解压 , false主线程中解压
        zipHandler = new ZipHandler(listening);
        start();
    }

    protected static class ZipHandler extends Handler {
        public static final int RESULT_SUCCESS = 0;
        public static final int RESULT_WORKING = 1;
        public static final int RESULT_ERROR = 2;
        public static final int RESULT_CANCELLED = 3;
        public static final int RESULT_FINISH = 4;

        private final OnUpdateListening listener;

        private ZipHandler(OnUpdateListening listener) {
            this.listener = listener;
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (listener == null)
                return;
            try {
                switch (msg.what) {
                    case RESULT_WORKING:
                        int percentDone = msg.arg1;
                        if (msg.obj instanceof String)
                            listener.onProgress(percentDone, String.valueOf(msg.obj));
                        else
                            listener.onProgress(percentDone, null);
                        break;
                    case RESULT_SUCCESS:
                        String versionName = msg.obj != null ? String.valueOf(msg.obj) : null;
                        listener.onSucceed(versionName);
                        break;
                    case RESULT_CANCELLED:
                        listener.onCancel();
                        break;
                    case RESULT_ERROR:
                        if (msg.obj instanceof Exception)
                            listener.onFailed((Exception) (msg.obj));
                        else
                            listener.onFailed(null);
                        break;
                    case RESULT_FINISH:
                        listener.onFinish();
                        break;
                }

            } catch (Exception e) {
                listener.onFailed(e);
            }
        }
    }

}
